/*
 *    GraphFileStream.java
 *    Copyright (C) 2011 University of Waikato, Hamilton, New Zealand
 *    @author Albert Bifet (abifet at cs dot waikato dot ac dot nz)
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package moa.streams;

import java.io.FileReader;
import java.io.IOException;

import moa.core.InstancesHeader;
import moa.core.ObjectRepository;
import moa.core.GraphExample;
import moa.core.Example;
import moa.options.AbstractOptionHandler;
import moa.options.FileOption;
import moa.tasks.TaskMonitor;

import moss.GraphReader;

public class GraphFileStream extends AbstractOptionHandler implements
        InstanceStream {

    @Override
    public String getPurposeString() {
        return "A Graph stream read from a file.";
    }
    private static final long serialVersionUID = 1L;

    public FileOption graphFileOption = new FileOption("graphFile", 'f',
            "File to load.", null, "arff", false);

    protected GraphReader fileReader;

    protected boolean hitEndOfFile;

    protected GraphExample lastInstanceRead;

    protected int numInstancesRead;

    public GraphFileStream() {
    }

    public GraphFileStream(String graphFileName) {
        this.graphFileOption.setValue(graphFileName);
        restart();
    }

    public GraphFileStream(String graphFileName, int classIndex) {
        this.graphFileOption.setValue(graphFileName);
        restart();
    }

    @Override
    public void prepareForUseImpl(TaskMonitor monitor,
            ObjectRepository repository) {
        restart();
    }

    public InstancesHeader getHeader() {
        return null;
    }

    public long estimatedRemainingInstances() {
        /*		double progressFraction = this.fileProgressMonitor
        .getProgressFraction();
        if ((progressFraction > 0.0) && (this.numInstancesRead > 0)) {
        return (long) ((this.numInstancesRead / progressFraction) - this.numInstancesRead);
        }*/
        return -1;
    }

    public boolean hasMoreInstances() {
        return !this.hitEndOfFile;
    }

    public Example nextInstance() {
        GraphExample prevInstance = this.lastInstanceRead;
        prevInstance.setWeight(1.0); //test weight
        this.hitEndOfFile = !readNextInstanceFromFile();
        return prevInstance;
    }

    public boolean isRestartable() {
        return true;
    }

    public void restart() {
        try {
            if (this.fileReader != null) {
                this.fileReader.close();
            }

            // The format of the graph file is the extension of the file
            // Example: database.smiles uses smiles format
            String fileName = this.graphFileOption.getValue();
            int dot = fileName.lastIndexOf(".");
            String format = fileName.substring(dot + 1);
            this.fileReader = GraphReader.createReader(new FileReader(fileName),
                    GraphReader.GRAPHS, format);
            this.numInstancesRead = 0;
            this.lastInstanceRead = null;
            this.hitEndOfFile = !readNextInstanceFromFile();
        } catch (IOException ioe) {
            throw new RuntimeException("graphFileStream restart failed.", ioe);
        }
    }

    protected boolean readNextInstanceFromFile() {
        try {
            if (this.fileReader.readGraph()) {
                float value;           /* value associated with the graph */
                int grp;             /* group of the graph */
                /** the threshold for the split into focus and complement */
                double thresh = 0.5;
                /** the group for graphs with a value below the threshold */
                int group = 0;
                value = this.fileReader.getValue();
                grp = (value > thresh) ? 1 - group : group;
                this.lastInstanceRead = new GraphExample(this.fileReader.getGraph(),
                        this.fileReader.getName(), value, grp);
                this.numInstancesRead++;
                return true;
            }
            System.out.println("**END OF FILE");
            return false;
        } catch (IOException ioe) {
            throw new RuntimeException(
                    "graphFileStream failed to read instance from stream.", ioe);
        }
    }

    public void getDescription(StringBuilder sb, int indent) {
        // TODO Auto-generated method stub
    }
}
